package cn.com.cifi.mars.util;

import cn.com.cifi.mars.common.enums.PriceReportGroupCodeEnum;
import cn.com.cifi.mars.constant.OrgTypeEunm;
import cn.com.cifi.mars.entity.DmDmValueReport;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * sheet 索引从 0 开始
 * row 索引从 0 开始
 * column 索引从 0 开始
 */
@Slf4j
public class PriceReportTemplate {

    private static final String TEMPLATE_PATH = "/template/price_report.xls";

    private HSSFWorkbook workbook;

    private HSSFSheet sheet;

    /**
     * 楼栋以及面积段 模板行索引
     */
    private int baseRow1Index = 3;


    /**
     * 楼栋以及面积段 模板行索引
     */
    private int baseRow2Index = 4;

    /**
     * 数据模板行 - 楼栋以及面积段
     */
    private HSSFRow baseRow1;


    /**
     * 数据模板行 - 楼栋及以上
     */
    private HSSFRow baseRow2;

    /**
     * 默认sheet索引
     */
    private int defaultSheetIndex = 0;


    /**
     * 数据开始行索引
     */
    private int dataBeginRow = 5;

    /**
     * 当前行标
     */
    private int currentDataRowCursor = dataBeginRow;

    /**
     * 基本信息结束列标
     */
    private int baseInfoEndColumn = 36;

    /**
     * 由于一开始模板没有需要根据不同级别区分不同样式的需求
     * 现在有了这种需求，直接改方法对原代码改动太大
     * 因此使用全局变量控制当前的组织机构类型
     */
    private OrgTypeEunm currentType;

    public PriceReportTemplate() {
        try {
            InputStream tempInputStream = PriceReportTemplate.class.getResourceAsStream(TEMPLATE_PATH);
            if (tempInputStream != null) {
                workbook = new HSSFWorkbook(tempInputStream);
                sheet = workbook.getSheetAt(defaultSheetIndex);
                //样式模板行
                baseRow1 = sheet.getRow(baseRow1Index);
                baseRow2 = sheet.getRow(baseRow2Index);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    public void setSheetName(String name){
        workbook.setSheetName(defaultSheetIndex,name);
    }


    /**
     * 批量插入行
     *
     * @param list
     */
    public synchronized void appendRows(List<Map<String, Object>> list) {
        for (Map<String, Object> map : list) {
            this.appendRow(map);
        }
    }

    public void copyRowStyle(HSSFRow from, HSSFRow to) {
        to.setHeight(from.getHeight());
        if (from != null && to != null && from != to && from.getRowStyle() != null) {
            to.setRowStyle(from.getRowStyle());
        }
    }

    public void copyCellStyle(HSSFCell from, HSSFCell to) {
        if (from != null && to != null && from != to && from.getCellStyle() != null) {
            to.setCellStyle(from.getCellStyle());
        }
    }

    public void copyCellStyle(HSSFCell to,OrgTypeEunm orgTypeEunm) {
        HSSFCell baseRow1Cell = baseRow1.getCell(to.getColumnIndex());
        if (orgTypeEunm == null){
            copyCellStyle(baseRow1Cell,to);
            return;
        }
        HSSFCell baseRow2Cell = baseRow2.getCell(to.getColumnIndex());
        switch (orgTypeEunm){
            case ORG_PRODUCTF:
                copyCellStyle(baseRow2Cell,to);
                break;
            case ORG_STAGE:
                copyCellStyle(baseRow2Cell,to);
                break;
            case ORG_GROUP:
                copyCellStyle(baseRow2Cell,to);
                break;
            case ORG_PRODUCT:
                copyCellStyle(baseRow2Cell,to);
                break;
            default:
                copyCellStyle(baseRow1Cell,to);
        }

    }


    public void appendSpaceColumn(HSSFRow row,AtomicInteger index){
        while (index.get() < baseInfoEndColumn){
            this.appendCell(row, index.addAndGet(1), "");
        }
    }

    /**
     * 插入行
     *
     * @param map
     */
    public synchronized void appendRow(Map<String, Object> map) {
        HSSFRow row = sheet.getRow(currentDataRowCursor);
        if (row == null) {
            row = sheet.createRow(currentDataRowCursor);
        }

        AtomicInteger index = new AtomicInteger(-1);
        //组织信息
        DmDmValueReport ref = (DmDmValueReport) map.get("ref");
        OrgTypeEunm orgTypeEunm = (OrgTypeEunm) map.get("orgType");
        this.currentType = orgTypeEunm;
        switch (orgTypeEunm){
            case ORG_PRODUCTF:
                copyRowStyle(baseRow2, row);
                this.appendCell(row, index.addAndGet(1), ref.getProjectName());
                this.appendCell(row, index.addAndGet(1), ref.getProjectCode());
                appendSpaceColumn(row,index);
                break;
            case ORG_STAGE:
                copyRowStyle(baseRow2, row);
                this.appendCell(row, index.addAndGet(1), ref.getProjectName());
                this.appendCell(row, index.addAndGet(1), ref.getProjectCode());
                this.appendCell(row, index.addAndGet(1), ref.getProjectfName());
                this.appendCell(row, index.addAndGet(1), ref.getProjectfCode());
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getProjectfEquityRatio())+"%");
                this.appendCell(row, index.addAndGet(1), ref.getOpMarketing());
                this.appendCell(row, index.addAndGet(1), ref.getIsAndTable() == 1?"是":"否");
                appendSpaceColumn(row,index);
                break;
            case ORG_GROUP:
                copyRowStyle(baseRow2, row);
                this.appendCell(row, index.addAndGet(1), ref.getProjectName());
                this.appendCell(row, index.addAndGet(1), ref.getProjectCode());
                this.appendCell(row, index.addAndGet(1), ref.getProjectfName());
                this.appendCell(row, index.addAndGet(1), ref.getProjectfCode());
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getProjectfEquityRatio())+"%");
                this.appendCell(row, index.addAndGet(1), ref.getOpMarketing());
                this.appendCell(row, index.addAndGet(1), ref.getIsAndTable() == 1?"是":"否");
                this.appendCell(row, index.addAndGet(1), ref.getGroupName());
                appendSpaceColumn(row,index);
                break;
/*            case ORG_PRO_TYPE:
                this.appendCell(row, index.addAndGet(1), ref.getProjectName());
                this.appendCell(row, index.addAndGet(1), ref.getProjectCode());
                this.appendCell(row, index.addAndGet(1), ref.getProjectfName());
                this.appendCell(row, index.addAndGet(1), ref.getProjectfCode());
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getProjectfEquityRatio()));
                this.appendCell(row, index.addAndGet(1), ref.getOpMarketing());
                this.appendCell(row, index.addAndGet(1), ref.getIsAndTable() == 1?"是":"否");
                this.appendCell(row, index.addAndGet(1), ref.getGroupName());
                this.appendCell(row, index.addAndGet(1), ref.getProductTypeName());
                this.appendCell(row, index.addAndGet(1), ref.getProductTypeCode());
                appendSpaceColumn(row,index);*/
//                break;
            case ORG_PRODUCT:
                copyRowStyle(baseRow2, row);
                this.appendCell(row, index.addAndGet(1), ref.getProjectName());
                this.appendCell(row, index.addAndGet(1), ref.getProjectCode());
                this.appendCell(row, index.addAndGet(1), ref.getProjectfName());
                this.appendCell(row, index.addAndGet(1), ref.getProjectfCode());
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getProjectfEquityRatio())+"%");
                this.appendCell(row, index.addAndGet(1), ref.getOpMarketing());
                this.appendCell(row, index.addAndGet(1), ref.getIsAndTable() == 1?"是":"否");
                this.appendCell(row, index.addAndGet(1), ref.getGroupName());
                this.appendCell(row, index.addAndGet(1), ref.getProductTypeName());
                this.appendCell(row, index.addAndGet(1), ref.getProductTypeCode());
                this.appendCell(row, index.addAndGet(1), ref.getProductName());
                this.appendCell(row, index.addAndGet(1), ref.getProductCode());
                appendSpaceColumn(row,index);
                break;
            case ORG_BUILD:
                copyRowStyle(baseRow1, row);
                this.appendCell(row, index.addAndGet(1), ref.getProjectName());
                this.appendCell(row, index.addAndGet(1), ref.getProjectCode());
                this.appendCell(row, index.addAndGet(1), ref.getProjectfName());
                this.appendCell(row, index.addAndGet(1), ref.getProjectfCode());
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getProjectfEquityRatio())+"%");
                this.appendCell(row, index.addAndGet(1), ref.getOpMarketing());
                this.appendCell(row, index.addAndGet(1), ref.getIsAndTable() == 1?"是":"否");
                this.appendCell(row, index.addAndGet(1), ref.getGroupName());
                this.appendCell(row, index.addAndGet(1), ref.getProductTypeName());
                this.appendCell(row, index.addAndGet(1), ref.getProductTypeCode());
                this.appendCell(row, index.addAndGet(1), ref.getProductName());
                this.appendCell(row, index.addAndGet(1), ref.getProductCode());
                this.appendCell(row, index.addAndGet(1), ref.getPhyBuildingName());
                this.appendCell(row, index.addAndGet(1), ref.getBuildingName());
                this.appendCell(row, index.addAndGet(1), ref.getBusinessTypeName());
                this.appendCell(row, index.addAndGet(1), ref.getFreeTypeName());
                this.appendCell(row, index.addAndGet(1), ref.getProTypeName());
                this.appendCell(row, index.addAndGet(1), "");
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getOpenTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getOpenTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getAdvanceSaleTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getAdvanceSaleTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getSupplyTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getSupplyTimeVirtual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getSupplyTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getOpenSaleTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getOpenSaleTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getCappingTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getCappingTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getCompletedTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getCompletedTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getCarryOverTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getCarryOverTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getActualDeliveryTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getActualDeliveryTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getContractDeliveryTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getContractDeliveryTimeActual()));
                break;
            default:
                copyRowStyle(baseRow1, row);
                this.appendCell(row, index.addAndGet(1), ref.getProjectName());
                this.appendCell(row, index.addAndGet(1), ref.getProjectCode());
                this.appendCell(row, index.addAndGet(1), ref.getProjectfName());
                this.appendCell(row, index.addAndGet(1), ref.getProjectfCode());
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getProjectfEquityRatio())+"%");
                this.appendCell(row, index.addAndGet(1), ref.getOpMarketing());
                this.appendCell(row, index.addAndGet(1), ref.getIsAndTable() == 1?"是":"否");
                this.appendCell(row, index.addAndGet(1), ref.getGroupName());
                this.appendCell(row, index.addAndGet(1), ref.getProductTypeName());
                this.appendCell(row, index.addAndGet(1), ref.getProductTypeCode());
                this.appendCell(row, index.addAndGet(1), ref.getProductName());
                this.appendCell(row, index.addAndGet(1), ref.getProductCode());
                this.appendCell(row, index.addAndGet(1), ref.getPhyBuildingName());
                this.appendCell(row, index.addAndGet(1), ref.getBuildingName());
                this.appendCell(row, index.addAndGet(1), ref.getBusinessTypeName());
                this.appendCell(row, index.addAndGet(1), ref.getFreeTypeName());
                this.appendCell(row, index.addAndGet(1), ref.getProTypeName());
                this.appendCell(row, index.addAndGet(1), ref.getMiniGranularityName());
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getOpenTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getOpenTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getAdvanceSaleTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getAdvanceSaleTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getSupplyTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getSupplyTimeVirtual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getSupplyTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getOpenSaleTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getOpenSaleTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getCappingTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getCappingTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getCompletedTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getCompletedTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getCarryOverTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getCarryOverTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getActualDeliveryTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getActualDeliveryTimeActual()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getContractDeliveryTime()));
                this.appendCell(row, index.addAndGet(1), ReportUtils.toString(ref.getContractDeliveryTimeActual()));
        }
        //全盘-已售货值
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.DYNAMIC_SALE_PRICE,orgTypeEunm);

        //全盘-存货货值
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.DYNAMIC_STOCK_PRICE,orgTypeEunm);

        //全盘-规划货值
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.DYNAMIC_PLAN_PRICE,orgTypeEunm);

        //全盘-总货值合计
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.DYNAMIC_TOTAL_PRICE,orgTypeEunm);

        //全盘-权益货值
        BigDecimal rightPrice = MathUtils.newBigDecimal((String) map.get(PriceReportGroupCodeEnum.DYNAMIC_RIGHT_PRICE.toFormatString("rightPrice"))).divide(MathUtils.NUM_10000,0,RoundingMode.HALF_UP);
        this.appendCell(row, index.addAndGet(1), ReportUtils.toString(rightPrice));

        //全盘-未推售车位
        BigDecimal carPlateCount = MathUtils.newBigDecimal((String) map.get(PriceReportGroupCodeEnum.DYNAMIC_UN_SEND_PRICE.toFormatString("carPlateCount")));
        BigDecimal carPlateTotalPrice = MathUtils.newBigDecimal((String) map.get(PriceReportGroupCodeEnum.DYNAMIC_UN_SEND_PRICE.toFormatString("carPlateTotalPrice"))).divide(MathUtils.NUM_10000,0,RoundingMode.HALF_UP);
        this.appendCell(row, index.addAndGet(1), ReportUtils.toString(carPlateCount));
        this.appendCell(row, index.addAndGet(1), ReportUtils.toString(carPlateTotalPrice));

        //土储-投资口径
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.LAND_INVEST_PRICE,orgTypeEunm);

        //土储-香港口径
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.LAND_HK_PRICE,orgTypeEunm);

        //未开工
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.UN_START_PRICE,orgTypeEunm);

        //在途 - 已开工未达形象进度
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.UN_REACH_PRICE,orgTypeEunm);

        //在途 - 已达形象进度未取证
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.UN_GET_CARD_PRICE,orgTypeEunm);

        //在途合计
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.ON_WAY_PRICE,orgTypeEunm);

        //存货 90 天内
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.STOCK_90_PRICE,orgTypeEunm);

        //存货 90 - 180 天内
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.STOCK_90_180_PRICE,orgTypeEunm);

        //存货 180 - 360 天内
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.STOCK_180_360_PRICE,orgTypeEunm);

        //存货 360 - 720 天内
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.STOCK_360_720_PRICE,orgTypeEunm);

        //存货 720 天外
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.STOCK_720_PRICE,orgTypeEunm);

        //存货 180 天外
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.STOCK_180_PRICE,orgTypeEunm);

        //存货 现房
        makeGroupColumn(map, row, index,PriceReportGroupCodeEnum.STOCK_EXIST_ROOM_PRICE,orgTypeEunm);

        currentDataRowCursor++;
    }

    private void makeGroupColumn(Map<String, Object> map, HSSFRow row, AtomicInteger index,PriceReportGroupCodeEnum groupCodeEnum,OrgTypeEunm orgTypeEunm) {
        BigDecimal roomCount = MathUtils.newBigDecimal((String) map.get(groupCodeEnum.toFormatString("roomCount")));
        BigDecimal carPlateCount = MathUtils.newBigDecimal((String) map.get(groupCodeEnum.toFormatString("carPlateCount")));
        BigDecimal area = MathUtils.newBigDecimal((String) map.get(groupCodeEnum.toFormatString("area")));
        BigDecimal roomTotalPrice = MathUtils.newBigDecimal((String) map.get(groupCodeEnum.toFormatString("roomTotalPrice")));
        BigDecimal carPlateTotalPrice = MathUtils.newBigDecimal((String) map.get(groupCodeEnum.toFormatString("carPlateTotalPrice")));
        BigDecimal totalPrice = MathUtils.bigDecimalAdd(roomTotalPrice,carPlateTotalPrice);
        BigDecimal roomAvgPrice = area.doubleValue() > 0?roomTotalPrice.divide(area,0, RoundingMode.HALF_UP): BigDecimal.ZERO;
        BigDecimal carAvgPrice = carPlateCount.intValue() > 0?carPlateTotalPrice.divide(carPlateCount,0,RoundingMode.HALF_UP):BigDecimal.ZERO;
        String isParkingStr = (String) map.get(groupCodeEnum.toFormatString("isParking"));
        Boolean isParking = "1".equals(isParkingStr);
        if (orgTypeEunm == OrgTypeEunm.ORG_GROUP || orgTypeEunm == OrgTypeEunm.ORG_STAGE || orgTypeEunm == OrgTypeEunm.ORG_PRODUCTF){
            this.appendCell(row, index.addAndGet(1), ReportUtils.split(roomCount, carPlateCount));
        }else {
            this.appendCell(row, index.addAndGet(1), ReportUtils.toString(isParking == null || !isParking ? roomCount:carPlateCount));
        }
        this.appendCell(row, index.addAndGet(1), ReportUtils.toString(area.setScale(2,RoundingMode.HALF_UP)));
        if (orgTypeEunm == OrgTypeEunm.ORG_GROUP || orgTypeEunm == OrgTypeEunm.ORG_STAGE || orgTypeEunm == OrgTypeEunm.ORG_PRODUCTF){
            this.appendCell(row, index.addAndGet(1), ReportUtils.split(roomAvgPrice,carAvgPrice));
        }else {
            this.appendCell(row, index.addAndGet(1), ReportUtils.toString(isParking == null || !isParking ? roomAvgPrice:carAvgPrice));
        }
        if (orgTypeEunm == OrgTypeEunm.ORG_GROUP || orgTypeEunm == OrgTypeEunm.ORG_STAGE || orgTypeEunm == OrgTypeEunm.ORG_PRODUCTF){
            this.appendCell(row, index.addAndGet(1), ReportUtils.split(totalPrice.divide(MathUtils.NUM_10000,0,RoundingMode.HALF_UP),roomTotalPrice.divide(MathUtils.NUM_10000,0,RoundingMode.HALF_UP),carPlateTotalPrice.divide(MathUtils.NUM_10000,0,RoundingMode.HALF_UP)));
        }else {
            this.appendCell(row, index.addAndGet(1), ReportUtils.toString(totalPrice.divide(MathUtils.NUM_10000,0,RoundingMode.HALF_UP)));
        }

    }

    /**
     * 插入列
     *
     * @param row
     * @param index
     * @param value
     */
    public synchronized void appendCell(HSSFRow row, int index, String value) {
        HSSFCell cell = row.getCell(index);
        if (cell == null) {
            cell = row.createCell(index);
        }
        copyCellStyle(cell,this.currentType);
        ReportUtils.setCellValue(cell,value);
    }


    /**
     * 导出
     *
     * @param outputStream
     * @throws IOException
     */
    public void write(OutputStream outputStream) throws IOException {
        //删除掉模板行
        int startRow = baseRow2Index + 1;
        int lastRowNum = sheet.getLastRowNum();
        if (startRow <= lastRowNum) {
            sheet.shiftRows(startRow, lastRowNum,-2);
        }else {
            sheet.removeRow(baseRow1);
            sheet.removeRow(baseRow2);
        }
        workbook.write(outputStream);
    }
}
